#include "MemIndex.hpp"

MemIndex::MemIndex( MemDatabase *db , string index_name , MemIndexType index_type )
{
	this->db = db ;
	
	this->index_name = index_name ;
	this->index_type = index_type ;
	
	memset( index_field_array , 0x00 , sizeof(index_field_array) );
	index_field_array_count = 0 ;
	
	memset( & (index_dataunit_tree) , 0x00 , sizeof(struct rb_root) );
	
	return;
}

bool MemIndex::Init( va_list valist )
{
	bool		bret ;
	
#if MDB_TRACE
	cout << "TRACE - MemIndex::MemIndex : MemDatabaseUtil::ConvertArgsToArray ..." << endl ;
#endif
	bret = MemDatabaseUtil::ConvertArgsToArray( valist , index_field_array , sizeof(index_field_array)/sizeof(index_field_array[0]) , & (index_field_array_count) ) ;
#if MDB_TRACE
	cout << "TRACE - MemIndex::MemIndex : MemDatabaseUtil::ConvertArgsToArray return[" << bret << "]" << endl ;
#endif
	if( bret != true )
	{
		db->SetError( MemDatabaseError::MDB_ERROR_TOO_MANY_FIELDS );
		return false;
	}
	
	return true;
}

MemIndex::~MemIndex()
{
	struct MemDataPage	*index_datapage = NULL ;
	
	for( list<MemDataPage*>::iterator it = index_data_pages.begin() ; it != index_data_pages.end() ; )
	{
		index_datapage = (*it) ;
#if MDB_TRACE
		cout << "TRACE - MemIndex::~MemIndex() : free index datapage[" << static_cast<void*>(index_datapage) << "]" << endl ;
#endif
		index_data_pages.erase( it++ );
		free(index_datapage);
	}
	
	return;
}

string MemIndex::GetIndexName()
{
	return index_name;
}

MemIndexType MemIndex::GetIndexType()
{
	return index_type;
}

struct MemField *MemIndex::GetIndexFieldArray()
{
	return index_field_array;
}

size_t MemIndex::GetIndexFieldArrayCount()
{
	return index_field_array_count;
}

bool MemIndex::MaintentIndexOnInsert( char *record_dataunit )
{
	struct MemDataPage			*index_datapage = NULL ;
	struct MemIndexDataUnit			*index_dataunit = NULL ;
	bool					bret ;
	
	if( index_data_pages.empty() )
		index_datapage = NULL ;
	else
		index_datapage = index_data_pages.back() ;
	if( index_datapage == NULL || IsFull(index_datapage) )
	{
#if MDB_TRACE
		if( index_datapage == NULL )
			cout << "TRACE - MemIndex::MaintentIndexOnInsert : datapage not found" << endl ;
		else
			cout << "TRACE - MemIndex::MaintentIndexOnInsert : datapage[" << index_datapage << "] end index data page full" << endl ;
#endif
		index_datapage = CreateDataPage( this , sizeof(struct MemIndexDataUnit) ) ;
		if( index_datapage == NULL )
		{
#if MDB_TRACE
			cout << "TRACE - MemIndex::MaintentIndexOnInsert : CreateDataPage failed" << endl ;
#endif
			db->SetError( MemDatabaseError::MDB_ERROR_ALLOC );
			return false;
		}
#if MDB_TRACE
		else
		{
			cout << "TRACE - MemIndex::MaintentIndexOnInsert : CreateDataPage ok" << endl ;
		}
#endif
		
#if MDB_TRACE
		cout << "TRACE - MemIndex::MaintentIndexOnInsert : index_data_pages.push_back datapage[" << index_datapage << "]" << endl ;
#endif
		index_data_pages.push_back( index_datapage );
	}
	
	index_dataunit = (struct MemIndexDataUnit *)GetUnusedDataUnit( index_datapage ) ;
	bret = AddIndexDataUnitTreeNode( record_dataunit , index_dataunit ) ;
	if( bret != true )
	{
#if MDB_TRACE
		cout << "TRACE - MemIndex::MaintentIndexOnInsert : AddIndexDataUnitTreeNode failed" << endl ;
#endif
		/* TODO */
		/* ... */
		return false;
	}
#if MDB_TRACE
	else
	{
		cout << "TRACE - MemIndex::MaintentIndexOnInsert : AddIndexDataUnitTreeNode ok" << endl ;
	}
#endif
	
	index_dataunit->index_datapage = index_datapage ;
	index_dataunit->record_dataunit = record_dataunit ;
	
	return true;
}

bool MemIndex::AddIndexDataUnitTreeNode( char *record_dataunit , struct MemIndexDataUnit *index_dataunit )
{
	char					*record_data = NULL ;
	register struct rb_node			**pp_add_node = NULL ;
	register struct rb_node			*p_parent = NULL ;
	register struct MemIndexDataUnit	*p = NULL ;
	register char				*p2 = NULL ;
	register size_t				index_field_array_no ;
	register struct MemField		*field = NULL ;
	int					result ;
	
	record_data = (char*)(record_dataunit+sizeof(struct MemRecordDataUnitHead)) ;
	
	pp_add_node = & (index_dataunit_tree.rb_node) ;
	while( *pp_add_node )
	{
		p_parent = (*pp_add_node) ;
		p = container_of( *pp_add_node , struct MemIndexDataUnit , index_dataunit_tree_node ) ;
		p2 = (char*)(p->record_dataunit+sizeof(struct MemRecordDataUnitHead)) ;
		
		result = 0 ;
		for( index_field_array_no = 0 , field = index_field_array ; index_field_array_no < index_field_array_count ; index_field_array_no++ , field++ )
		{
#if MDB_TRACE
			cout << "TRACE - MemIndex::AddIndexDataUnitTreeNode : record_data[" << static_cast<void*>(record_data) << "] p2[" << static_cast<void*>(p2) << "] field_offset[" << field->field_offset << "] field_size[" << field->field_size << "]" << endl ;
			MemDatabaseUtil::printhex( record_data+field->field_offset , field->field_size );
			cout << endl ;
			MemDatabaseUtil::printhex( p2+field->field_offset , field->field_size );
			cout << endl ;
#endif
			result = memcmp( record_data+field->field_offset , p2+field->field_offset , field->field_size ) ;
			if( result )
				break;
		}
		if( result < 0 )
		{
			pp_add_node = & ((*pp_add_node)->rb_left) ;
		}
		else if( result > 0 )
		{
			pp_add_node = & ((*pp_add_node)->rb_right) ;
		}
		else
		{
			if( index_type == MemIndexType::MDB_UNIQUEINDEX )
				return false;
			pp_add_node = & ((*pp_add_node)->rb_right) ;
		}
	}
	
	rb_link_node( & (index_dataunit->index_dataunit_tree_node) , p_parent , pp_add_node );
	rb_insert_color( & (index_dataunit->index_dataunit_tree_node) , & (index_dataunit_tree) );
	
	return true;
}

struct MemIndexDataUnit *MemIndex::QueryIndexDataUnitTreeNode( void *record_buffer )
{
	register struct rb_node			**pp_add_node = NULL ;
	register struct MemIndexDataUnit	*p = NULL ;
	register char				*p2 = NULL ;
	register size_t				index_field_array_no ;
	register struct MemField		*field = NULL ;
	int					result ;
	
	pp_add_node = & (index_dataunit_tree.rb_node) ;
	while( *pp_add_node )
	{
		p = container_of( *pp_add_node , struct MemIndexDataUnit , index_dataunit_tree_node ) ;
		p2 = (char*)(p->record_dataunit+sizeof(struct MemRecordDataUnitHead)) ;
		
		result = 0 ;
		for( index_field_array_no = 0 , field = index_field_array ; index_field_array_no < index_field_array_count ; index_field_array_no++ , field++ )
		{
			result = memcmp( (char*)record_buffer+field->field_offset , p2+field->field_offset , field->field_size ) ;
			if( result )
				break;
		}
		if( result < 0 )
		{
			pp_add_node = & ((*pp_add_node)->rb_left) ;
		}
		else if( result > 0 )
		{
			pp_add_node = & ((*pp_add_node)->rb_right) ;
		}
		else
		{
			return p;
		}
	}
	
	return NULL;
}

